import * as system from './system'
import { WIFI_SECURITY_TYPE } from './constant';
import { log, waitTime } from '../../util/index';

import type { WifiDeviceConfig, WifiCommonHandler } from './type'

const TAG = 'connect_wifi_service'

class WifiConnect {
  private maxWaitStateNum = 10
  private maxWaitConnectNum = 30
  private stateHandlerMap: Map<string | symbol, WifiCommonHandler> = new Map()
  private connectionHandlerMap: Map<string | symbol, WifiCommonHandler> = new Map()
  private rssiHandlerMap: Map<string | symbol, WifiCommonHandler> = new Map()

  constructor() {
    this.init()
  }

  private init() {
    system.onWifiStateChange((state) => {
      log.info(TAG, 'onWifiStateChange', state)
      this.stateHandlerMap.forEach(handler => {
        handler(state)
      })
    })
    system.onWifiConnectionChange((state) => {
      log.info(TAG, 'onWifiConnectionChange', state)
      this.connectionHandlerMap.forEach(handler => {
        handler(state)
      })
    })
    system.onWifiRssiChange((state) => {
      log.info(TAG, 'onWifiRssiChange', state)
      this.rssiHandlerMap.forEach(handler => {
        handler(state)
      })
    })
  }

  private async waitState(state: boolean): Promise<boolean> {
    let currentState = system.isWifiActive()
    let num = 0
    while (num < this.maxWaitStateNum && currentState !== state) {
      await waitTime()
      currentState = system.isWifiActive()
      num = num + 1
    }
    return currentState === state
  }

  private async waitConnect(state: boolean): Promise<boolean> {
    let currentState = system.isConnected()
    let num = 0
    while (num < this.maxWaitConnectNum && currentState !== state) {
      await waitTime()
      currentState = system.isConnected()
      num = num + 1
    }
    return currentState === state
  }

  // private isActive(): boolean {
  //   return system.isWifiActive()
  // }
  //
  // private isConnected(): boolean {
  //   return system.isConnected()
  // }

  private async enable(): Promise<boolean> {
    const isWifiActive = system.isWifiActive()
    let result = false
    if (isWifiActive) {
      result = true
    } else {
      result = system.enableWifi()
      if (result) {
        result = await this.waitState(true)
      }
    }
    return result
  }

  // private async disable(): Promise<boolean> {
  //   const isWifiActive = system.isWifiActive()
  //   let result = false
  //   if (isWifiActive) {
  //     result = system.disableWifi()
  //     if (result) {
  //       result = await this.waitState(false)
  //     }
  //   } else {
  //     result = true
  //   }
  //   return result
  // }
  //
  // private async getLinkedInfo(): Promise<WifiLinkedInfo> {
  //   if (system.isConnected()) {
  //     return await system.getLinkedInfo()
  //   } else {
  //     return null
  //   }
  // }

  private removeOtherDeviceConfig(ssid: string) {
    const configs = system.getDeviceConfigs();
    for (let i = 0; i < configs.length; i++) {
      if (configs[i].ssid !== ssid) {
        system.removeDevice(configs[i].netId)
      }
    }
  }

  // private removeDeviceConfig(ssid: string) {
  //   const configs = system.getDeviceConfigs();
  //   const config = configs.find(item => item.ssid === ssid)
  //   if (config) {
  //     system.removeDevice(config.netId)
  //   }
  // }

  async connect(config: WifiDeviceConfig): Promise<boolean> {
    log.info(TAG, 'connect start', JSON.stringify(config))
    let result = await this.enable()
    const isConnected = system.isConnected()
    log.info(TAG, 'connect isConnected', isConnected)
    if (isConnected) {
      const linkedInfo = await system.getLinkedInfo()
      if (linkedInfo.ssid === config.ssid) {
        return true
      }
      result = system.disconnect()
      log.info(TAG, 'connect disconnect', result)
      if (result) {
        result = await this.waitConnect(false)
        log.info(TAG, 'connect disconnect result', result)
      }
    }
    if (result) {
      result = system.connectToDevice(config)
      log.info(TAG, 'connect connectToDevice', result)
    }
    if (result) {
      result = await this.waitConnect(true)
      log.info(TAG, 'connect result', result)
    }
    if (result) {
      this.removeOtherDeviceConfig(config.ssid)
    }
    return result
  }

  async disconnect(): Promise<boolean> {
    let result = true
    const isConnected = system.isConnected()
    log.info(TAG, 'disconnect isConnected', isConnected)
    if (!isConnected) {
      return result
    }
    result = system.disconnect()
    log.info(TAG, 'disconnect op', result)
    if (result) {
      result = await this.waitConnect(false)
      log.info(TAG, 'disconnect result', result)
    }
    return result
  }

  offStateChange(key?: string) {
    if (key === undefined) {
      this.stateHandlerMap.clear()
    } else {
      if (this.stateHandlerMap.has(key)) {
        this.stateHandlerMap.delete(key)
      }
    }
  }

  onStateChange(handler: WifiCommonHandler, key: string | symbol = Symbol()) {
    this.stateHandlerMap.set(key, handler)
  }
}

const wifiConnect = new WifiConnect()

export {
  wifiConnect, WIFI_SECURITY_TYPE
}

export type {
  WifiDeviceConfig
}